/**
 * @file HaierU+Uart.c
 * @brief
 * @author xuesong (wenshaoliu@foxmail.com)
 * @version 1.0
 * @date 2024-08-17
 *
 * @copyright Copyright (c) 2024  by xuesong
 *
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version <th>Author  <th>Description
 * <tr><td>2024-08-17     <td>1.0     <td>xuesong   <td>内容
 * </table>
 */
#include <stdlib.h>
#include "HaierU+Uart.h"
#include "LoopFIFO.h"
#include "streambuffer.h"
#include "crc.h"
//--------------------------------------------------
#include "stdio.h"
#define pvPortMalloc malloc
#define vPortFree free
#define LOG(...) printf(__VA_ARGS__)
//---------------------------------------------------------------
static uint8_t EscapeHaierHead(uint8_t *pData, uint8_t Len);
//---------------------------------------------------------------
const uint8_t DirectTypeID[] = {0x20, 0x54, 0xa0, 0xdc, 0x55, 0x22, 0x8f, 0x74, 0x15, 0x0e, 0xee, 0xc6, 0x8f, 0xea, 0x28, 0x00, 0x00, 0x00, 0x65, 0x7e, 0x03, 0xef, 0x45, 0x15, 0x34, 0x4d, 0x38, 0x57, 0x47, 0x04, 0x60, 0x40};
const uint8_t DirectKey[] = {0x62, 0x8a, 0x88, 0x4E, 0xD8, 0x98, 0x45, 0x42, 0xa8, 0x98, 0xd7, 0xb5, 0x97, 0xe6, 0x1A, 0xEd};
//---------------------------------------------------------------
#define UartRxBufferSize 256
uint8_t pcUartRxBuf[UartRxBufferSize];
fifo_data_t xUartFifoRx;
#define UartTxBufferSize 512
uint8_t pcUartTxBuf[UartTxBufferSize];
StreamBufferDef xUartTxStreamBuffer;
//---------------------------------------------------------------
void UartTransmitInit(void)
{
    xFifoBufferStaticCreate(&xUartFifoRx, pcUartRxBuf, UartRxBufferSize);
    xStreamBufferStaticCreate(&xUartTxStreamBuffer, pcUartTxBuf, UartTxBufferSize);
}
/**
 * @brief
 * @param  sFifo            MyParamDoc
 */
void HaiErUartDataDecode(fifo_data_t *sFifo)
{
    fleamStruct_t uartRxFleam;
    uint16_t unProcessBytes = getXFifoBufferOccupy(sFifo);
    uint8_t data[256];
    uint16_t readIndex = 0;
    uint16_t readLen;
    uint8_t EscapeCnt = 0;
    uint8_t EscapeOffSet;
    while (unProcessBytes > 3)
    {
        readLen = 3;
        if (xFifoBufferPeek(sFifo, data, readIndex, readLen) != Fifo_NO_ERR) // 数据没有接收完
            break;
        uartRxFleam.fleamHead = data[0];
        uartRxFleam.fleamHead <<= 8;
        uartRxFleam.fleamHead |= data[1];
        uartRxFleam.fleamLen = data[2];
        if (HaierFleamHead != uartRxFleam.fleamHead)
        {
            xFifoBufferRead2X(sFifo, 1);
            unProcessBytes = getXFifoBufferOccupy(sFifo);
            LOG("UR Drop:%02X", data[0]);
            continue;
        }

        readIndex = 3;
        readLen = uartRxFleam.fleamLen;
        EscapeOffSet = 0;
        while (1)
        {
            EscapeCnt = xFifoBufferPeek(sFifo, &data[EscapeOffSet], readIndex, readLen);
            if (EscapeCnt != Fifo_NO_ERR) // 数据没有接收完
                break;
            readIndex += readLen;
            EscapeCnt = EscapeHaierHead(&data[EscapeOffSet], readLen);
            if (EscapeCnt)
            {
                EscapeOffSet = readLen - EscapeCnt;
                readLen = EscapeCnt;
            }
            else
            {
                break;
            }
        }
        if (EscapeCnt) // 数据没有接收完
            break;
        uartRxFleam.sumCheck = data[uartRxFleam.fleamLen - 1];
        memcpy(&uartRxFleam.payload.addrSymbol, data, sizeof(uartRxFleam.payload.addrSymbol));
        if (uartRxFleam.payload.addrSymbol.Flag.Bits.CrcCheckEn)
        {
            readLen = 2;
            if (xFifoBufferPeek(sFifo, data, readIndex, readLen) != Fifo_NO_ERR) // 数据没有接收完
                break;
            readIndex += readLen;
            uartRxFleam.crcCheck = data[0];
            uartRxFleam.crcCheck <<= 8;
            uartRxFleam.crcCheck |= data[1];
        }
        uartRxFleam.payload.fleamType = data[sizeof(uartRxFleam.payload.addrSymbol)];
        uartRxFleam.payloadData = &data[sizeof(uartRxFleam.payload.addrSymbol) + 1];
        xFifoBufferRead2X(sFifo, readIndex);
        LOG("uart process len:%d", readIndex);
        switch (uartRxFleam.payload.fleamType)
        {
        case D_AskDeviceVer:
        {
        }
        break;
        case D_AskDeviceId:
        {
        }
        break;
        case D_CTRL:
        {
        }
        break;
        }
    }
}

/**
 * @brief 转义解包编码值
 * @param  pData            待解包数据
 * @param  Len              待捷豹数据长度
 * @return uint8_t
 */
static uint8_t EscapeHaierHead(uint8_t *pData, uint8_t Len)
{
    uint8_t EscapeCnt = 0;
    for (uint8_t i = 0; i < Len - 1; i++)
    {
        if (pData[i] == 0xFF && pData[i + 1] == 0x55)
        {
            for (uint8_t j = i + 1; j < Len - 1; j++)
            {
                pData[j] = pData[j + 1];
            }
            Len--;
            EscapeCnt++;
        }
    }
    return EscapeCnt;
}

static int8_t EscapeCodeHaierHead(uint8_t *pData, uint8_t *payloadLen, uint8_t bufferLen)
{
    int8_t EscapeCnt = 0;
    for (uint8_t i = 0; i < *payloadLen; i++)
    {
        if (pData[i] == 0xFF)
        {
            EscapeCnt++;
        }
    }
    if (EscapeCnt)
    {
        if ((*payloadLen + EscapeCnt) <= bufferLen)
        {
            *payloadLen += EscapeCnt;
            for (uint8_t i = 0; i < *payloadLen; i++)
            {
                if (pData[i] == 0xFF)
                {
                    for (uint8_t j = *payloadLen; j > (i + 1); j--)
                    {
                        pData[j] = pData[j - 1];
                    }
                    pData[i + 1] = 0x55;
                    i++;
                }
            }
        }
        else
        {
            EscapeCnt = 0 - EscapeCnt;
        }
    }
    return EscapeCnt;
}
static uint8_t add8SumCheck(uint8_t *pData, uint8_t Len)
{
    uint8_t addSum = 0;
    for (uint8_t i = 0; i < Len; i++)
    {
        addSum += pData[i];
    }
    return addSum;
}

static void printDump(void *pData, uint8_t Len)
{
    uint8_t *point = (uint8_t *)pData;
    for (uint8_t i = 0; i < Len; i++)
    {
        printf("%02X ", *point++);
    }
    printf("\r\n");
}
/**
 * @brief
 * @param  fleam            point in buffer
 * @param  bufferSize       buffer size
 * @param  needCrc          is need Crc16
 * @return int8_t
 */
static int8_t TxFleam2SendStream(fleamStruct_t *fleam, uint16_t bufferSize, bool needCrc)
{
    int8_t cnt = 0;
    uint8_t payloadDataIndex = fleam->fleamLen - D_PAYLOAD_DATA_LEN_FLEAM_LEN;
    printf("really data without check:");
    printDump(&fleam->fleamHead, payloadDataIndex + 10);
    if (needCrc)
    {
        // fleam->crcCheck = getCrcData(&fleam->fleamLen, fleam->fleamLen);
        fleam->crcCheck = ModBusCrc16(0xFFFF, &fleam->fleamLen, fleam->fleamLen);
        cnt = EscapeCodeHaierHead(fleam->payloadData, &payloadDataIndex, bufferSize - D_PAYLOAD_DATA_LEN_OFFSET2BUFF - 7);
    }
    else
    {
        cnt = EscapeCodeHaierHead(fleam->payloadData, &payloadDataIndex, bufferSize - D_PAYLOAD_DATA_LEN_OFFSET2BUFF - 5);
    }
    if (cnt >= 0) // 正常无错误
    {
        fleam->payloadData[payloadDataIndex++] = add8SumCheck(&fleam->fleamLen, payloadDataIndex + D_PAYLOAD_DATA_LEN_FLEAM_LEN);
        if (needCrc)
        {
            fleam->payloadData[payloadDataIndex++] = (fleam->crcCheck >> 8) & 0xFF;
            fleam->payloadData[payloadDataIndex++] = (fleam->crcCheck) & 0xFF;
        }
        // xStreamBufferWrite(&xUartTxStreamBuffer, &fleam->fleamHead, payloadDataIndex + 10);
        printf("send buffer:");
        printDump(&fleam->fleamHead, payloadDataIndex + 10);
    }
    else
    {
        uint16_t tempBufferLen = 0;
        uint8_t *tempPoint = NULL;
        if (needCrc)
        {
            tempBufferLen = payloadDataIndex + D_PAYLOAD_DATA_LEN_OFFSET2BUFF - cnt;
        }
        else
        {
            tempBufferLen = payloadDataIndex + D_PAYLOAD_DATA_LEN_OFFSET2BUFF - 2 - cnt;
        }
        tempPoint = malloc(tempBufferLen);
        if (tempPoint)
        {
            memcpy(tempPoint, &fleam->fleamHead, fleam->fleamLen + 2);
            EscapeCodeHaierHead(&tempPoint[10], &payloadDataIndex, payloadDataIndex - cnt);
            tempPoint[10 + payloadDataIndex++] = add8SumCheck(&tempPoint[2], payloadDataIndex + D_PAYLOAD_DATA_LEN_FLEAM_LEN);
            if (needCrc)
            {
                tempPoint[10 + payloadDataIndex++] = (fleam->crcCheck >> 8) & 0xFF;
                tempPoint[10 + payloadDataIndex++] = (fleam->crcCheck) & 0xFF;
            }
            // xStreamBufferWrite(&xUartTxStreamBuffer, tempPoint, payloadDataIndex + 10);
            printf("send buffer:");
            printDump(tempPoint, payloadDataIndex + 10);
            free(tempPoint);
        }
        else
        {
            LOG("send buffer fleam not enough");
        }
    }
}

void AckHaierDeviceVer(uint8_t fleamFlagNum)
{
    fleamStruct_t *uartTxFleam = NULL;
    uint8_t TempBuffer[63];
    uint8_t payloadDataIndex;
    DeviceFunctionFlag_t const DeviceFlag = {
        .Flag.Bits.reserve01 = 0,
        .Flag.Bits.SupportCrc = 1,
        .Flag.Bits.BaseBoardAsk = 1,
        .Flag.Bits.MultiSlaver = 0,
        .Flag.Bits.isDevice = 1,
        .Flag.Bits.DeviceKey = 0,
        .Flag.Bits.NewNetWork = 1,
        .Flag.Bits.MeshDevice = 0,
        .Flag.Bits.PcBoard = 0,
        .Flag.Bits.FlagAddr = 1,
        .Flag.Bits.SplitFleam = 0,
    };
    uartTxFleam = (fleamStruct_t *)TempBuffer;
    uartTxFleam->fleamHead = HaierFleamHead;
    memset(&uartTxFleam->payload.addrSymbol, 0, sizeof(uartTxFleam->payload.addrSymbol));
    uartTxFleam->payload.addrSymbol.fleamFlagNum = fleamFlagNum;
    uartTxFleam->payload.addrSymbol.sourceAddr = DirectSlaverAddr;
    uartTxFleam->payload.addrSymbol.aimAddr = NetModeAddr;
    uartTxFleam->payload.fleamType = D_DeviceAckVer;
    uartTxFleam->payloadData = (&uartTxFleam->payload.fleamType) + 1;
    payloadDataIndex = 0;
    memcpy(&uartTxFleam->payloadData[payloadDataIndex], DeviceProtocolVer, 8);
    payloadDataIndex += 8;
    memcpy(&uartTxFleam->payloadData[payloadDataIndex], DeviceSoftVer, 8);
    payloadDataIndex += 8;
    // uartTxFleam->payloadData[payloadDataIndex] = UART_ENCRYPTION;
    // payloadDataIndex += 3; // 保留2个字节
    uartTxFleam->payloadData[payloadDataIndex++] = 0xFF;
    uartTxFleam->payloadData[payloadDataIndex++] = 0xFF;
    uartTxFleam->payloadData[payloadDataIndex++] = 0xFF;
    memcpy(&uartTxFleam->payloadData[payloadDataIndex], DeviceHardVer, 8);
    payloadDataIndex += 8;
    uartTxFleam->payloadData[payloadDataIndex++] = CommunicateType;
    memcpy(&uartTxFleam->payloadData[payloadDataIndex], SoftApName, 8);
    payloadDataIndex += 8;
    uartTxFleam->payloadData[payloadDataIndex++] = (DeviceFlag.Flag.Byte >> 8) & 0xFF;
    uartTxFleam->payloadData[payloadDataIndex++] = (DeviceFlag.Flag.Byte) & 0xFF;
    uartTxFleam->payloadData[payloadDataIndex++] = DirectSlaverAddr;
    uartTxFleam->payloadData[payloadDataIndex++] = 0;
    uartTxFleam->fleamLen = payloadDataIndex + D_PAYLOAD_DATA_LEN_FLEAM_LEN;
    TxFleam2SendStream(uartTxFleam, sizeof(TempBuffer), true);
}
